package com.hontech.bv.net.device

import com.hontech.bv.codec.decodeUint16
import com.hontech.bv.codec.decodeUint32
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream

/**
 * proto define
 * [0:1] E1 1E
 * [2:5] size
 * [6:7] req
 * [9:n] body
 */

const val PROTO_HEAD = 0xE11E

var tcpRecvProg = 0
    private set

fun InputStream.readExact(n: Int): ByteArray {
    val buf = ByteArray(n)
    var index = 0
    tcpRecvProg = 0
    while (index < n) {
        val ret = read(buf, index, index - n)
        if (ret <= 0) {
            throw IOException("tcp socket closed")
        }
        index += ret
        tcpRecvProg = index * 100 / n
    }
    return buf
}

fun InputStream.readFrame(): Frame {
    val headBuf = readExact(8)
    val head = decodeUint16(headBuf, 0)
    if (head != PROTO_HEAD) {
        throw IllegalStateException("无效的数据帧头")
    }

    val size = decodeUint32(headBuf, 2)
    if (size < 8) {
        throw IllegalStateException("无效的数据帧长度")
    }

    val req = decodeUint16(headBuf, 6)

    if (size == 8) {
        return Frame(req, null)
    }
    val body = readExact(size - 8)

    return Frame(req, body)
}

inline fun <reified T> InputStream.readJson(req: Int): T {
    val frame = readFrame()
    if (frame.req != req) {
        throw IllegalStateException("req 错误 :$req ${frame.req}")
    }
    return frame.parse()
}

inline fun <reified T> OutputStream.writeJson(req: Int, v: T) {
    val buf = Frame.fromJson(req, v).build()
    write(buf)
}

